home *** CD-ROM | disk | FTP | other *** search
- // (c) Jean MICHEL June 1993 -- any modifications must be signaled to the
- // author
-
- // cell.cpp: classes to compute life generations. This is completely
- // independant from windows, and can be used Con any system
-
- #include "cell.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <io.h>
- #include <string.h>
- #include "efns.h"
- #define MAXCELLS 16000
- #define INFINI 0xfffdfffal
- static cell_type temp[MAXCELLS];
-
- static cell_type *copy(cell_type *pw,int pop)
- { cell_type *v=new cell_type[pop+1];
- for(int i=0;i<pop;i++)v[i]=pw[i];
- v[i]=INFINI;
- return v;
- }
-
- cellpop::cellpop(cellpop&w){pop=w.pop;v=copy(w.v,pop);}
-
- void cellpop::clear_pop(){delete[] v;v=copy(NULL,pop=0);}
-
- cellpop::cellpop(){v=NULL;pop=0;}
-
- void cellpop::operator=(const cellpop& w)
- {if(v)delete[] v;v=copy(w.v,pop=w.pop);}
-
- cellpop::~cellpop(){if(v)delete[] v;}
-
- cellpop::cellpop(int lg)
- { pop=lg;
- v=new cell_type[pop+1];
- for(int i=0;i<pop;i++)v[i]=cell_type(i,0);
- v[i]=INFINI;
- }
-
- BOOL cellpop::operator==(cellpop& w)
- { if(pop!=w.pop)return FALSE;
- for(int i=0;i<pop;i++)if(v[i]!=w.v[i])return FALSE;
- return TRUE;
- }
-
- BOOL cellpop::in(cell_type c)
- { for(int i=0;i<pop;i++)if(v[i]==c)return TRUE;
- return FALSE;
- }
-
- void cellpop::nextgen(cellpop& w)/* v=nextgen from w */
- { INTCELL *ind[9]/* indexes in w for neighb*/;
- static INTCELL neighb[9]; // neighbours
- for(int i=0;i<9;i++){neighb[i]=0;ind[i]=(INTCELL *)w.v;}
- static long d[9]={-BASE-1,-BASE,1-BASE,-1,0,1,BASE-1,BASE,BASE+1};
- /* relative position of neighbours */
- INTCELL x,lim=INFINI+d[0];
- int iv=0;
- for(INTCELL z=0/* previous cell */;z<lim;z=x)
- { INTCELL *n=neighb;int sum=0;
- x=INFINI; // will become current cell
- for (i=0;i<9;i++,n++)
- { if(*n==z)*n=d[i]+*ind[i]++;
- if(*n<x){x=*n;sum=1;}
- else if(*n==x)sum++;
- }
- if(sum==3 ||(sum==4 && neighb[4]==x))
- { if(iv>=MAXCELLS)
- { efns(WARNING_,"%d: too many cells",MAXCELLS);
- delete[]v;v=NULL;
- return;
- }
- temp[iv++]=cell_type(x);
- }
- }
- delete[]v;v=copy(temp,pop=iv);
- }
-
- static int compar(const void *a,const void *b)
- { unsigned long x=*(unsigned long *)a,y=*(unsigned long *)b;
- return x<y?-1:(x>y?1:0);}
-
- void cellpop::transform(char orientation)
- { int dirx=orientation&0x1?-1:1,diry=orientation&0x2?-1:1;
- BOOL rot=orientation&0x4;
- for(int i=0;i<pop;i++)
- v[i]=cell_type(dirx*(rot?v[i].celly():v[i].cellx()),
- diry*(rot?v[i].cellx():v[i].celly()));
- qsort(v,pop,sizeof(cell_type),compar);
- }
-
- void cellpop::add(cellpop&w,cellpop &shape,cell_type offset,int mode)
- { int iv=0,iw=0;
- for(int is=0;is<shape.pop;is++)
- { cell_type c=shape.v[is]+offset;
- while(w.v[iw]<c)temp[iv++]=w.v[iw++];
- if(w.v[iw]>c){if(mode!=LAY_OFF)temp[iv++]=c;}
- else if(mode==LAY_ON)temp[iv++]=w.v[iw++];
- else iw++;
- }
- while(iw<w.pop)temp[iv++]=w.v[iw++];
- v=copy(temp,pop=iv);
- }
-
- cell_type cellpop::lastx(void)
- { cell_type res;int x=-cell_type(INFINI).cellx();
- for(int i=0;i<pop;i++)
- if(v[i].cellx()>=x){x=v[i].cellx();res=v[i];}
- return res;
- }
-
- cell_type cellpop::firstx(void)
- { cell_type res;int x=cell_type(INFINI).cellx();
- for(int i=0;i<pop;i++)
- if(v[i].cellx()<x){x=v[i].cellx();res=v[i];}
- return res;
- }
-
- cell_type cellpop::firsty(void)
- { cell_type res;int y=cell_type(INFINI).cellx();
- for(int i=0;i<pop;i++)
- if(v[i].celly()<y){y=v[i].celly();res=v[i];}
- return res;
- }
-
- cell_type cellpop::lasty(void)
- { cell_type res;int y=-cell_type(INFINI).cellx();
- for(int i=0;i<pop;i++)
- if(v[i].celly()>=y){y=v[i].celly();res=v[i];}
- return res;
- }
-
- void cellpop::erase_rect(cell_type start,cell_type end)
- { int y=0;
- for(int x=0;x<pop;x++)
- if(v[x].cellx()<start.cellx() || v[x].cellx()>=end.cellx() ||
- v[x].celly()<start.celly() || v[x].celly()>=end.celly()) v[y++]=v[x];
- v[y]=INFINI;
- pop=y;
- }
-
- void cellpop::save_rect(char *FileName,cell_type start,cell_type end)
- { FILE *fp=fopen(FileName,"w");
- int x=start.x,y=start.y;
- if(fp==NULL){ efns(WARNING_|FILE_,FileName);return;}
- for(int i=0;i<pop;i++)
- if(v[i].cellx()>=start.cellx() && v[i].cellx()<end.cellx() &&
- v[i].celly()>=start.celly() && v[i].celly()<end.celly())
- { for(;y<v[i].y;y++){fprintf(fp,"\n");x=start.x;}
- for(;x<v[i].x;x++)fprintf(fp," ");
- fprintf(fp,"o");x++;
- }
- fprintf(fp,"\n");
- fclose(fp);
- }
-
- void cellpop::save(char *FileName)
- { save_rect(FileName,cell_type(firstx().cellx(),firsty().celly()),
- cell_type(1+lastx().cellx(),1+lasty().celly()));
- }
-
- cellpop::cellpop(char *string)
- { pop=0;v=0;
- int x=0,y=0;
- for(char *s=string;*s;s++)
- switch(*s)
- { case '\n':y++;x=0;break;
- case '\r':break;
- case ' ':case '.':x++;break;
- case '$':x+=10;break;
- case '\t': x+=8-x%8;break;
- case 'o':case 'O':
- if(pop==MAXCELLS){efns(WARNING_,"%d: too many cells",MAXCELLS);return;}
- temp[pop++]=cell_type(x,y);
- x++;break;
- default: efns(WARNING_,"invalid data in string <%.15s>",
- s-5<string?string:s-5);
- return;
- }
- v=copy(temp,pop);
- }
-
- cellpop readfile(char *FileName)
- { cellpop res;
- FILE *f=fopen(FileName,"rb");
- if(f==NULL)
- { efns(WARNING_|FILE_,FileName);
- return res;
- }
- long flen=filelength(fileno(f));
- if(flen>65534u)
- { efns(WARNING_,"file `%s' too big: %ld bytes",FileName,flen) ;
- fclose(f);return res;
- }
- char *s=new char[(unsigned)flen];
- if(flen!=fread(s,1,(unsigned)flen,f))
- { efns(WARNING_|FILE_,FileName);
- delete[]s;fclose(f);return res;
- }
- fclose(f);
- s[flen]=0; res=cellpop(s);
- delete[]s;
- return res;
- }
-
-
- struct named_shape
- { char *name;
- cellpop shape;
- named_shape *next,*prev;
- };
- static named_shape *shapeptr=NULL;
-
- static int shapeidx=-1;
-
- char *getshapename(int i)
- { if(!shapeptr)return NULL;
- while(i>shapeidx && shapeptr->next)
- { shapeidx++;shapeptr=shapeptr->next;}
- if(i>shapeidx)return NULL;
- while(i<shapeidx && shapeptr->prev)
- { shapeidx--;shapeptr=shapeptr->prev;}
- if(i<shapeidx)return NULL;
- return shapeptr->name;
- }
-
- cellpop getshape(int i)
- { char *s=getshapename(i);
- return shapeptr->shape;
- }
-
- #define MAXNAME 30
- void readshapelib(char *FileName)
- { FILE *f=fopen(FileName,"rb");
- int line=1,c;
- char name[MAXNAME+1];
- named_shape *oldptr=NULL;
- if(f==NULL)
- { efns(WARNING_|FILE_,FileName);
- return;
- }
- if(shapeptr)
- { while(shapeptr->next)
- { shapeidx++;shapeptr=shapeptr->next;}
- oldptr=shapeptr;
- }
- while((c=getc(f))!=EOF)switch(c)
- { case '|': while((c=getc(f))!=EOF && c!='\n');line++;break;
- case '[': for(char *n=name;(c=getc(f))!=']';n++)
- { if(n>=name+MAXNAME)
- { efns(WARNING_,"error in %s line %d: name too long (>%d chars)",
- FileName,line,MAXNAME);
- goto fin;
- }
- if(c==EOF)
- { efns(WARNING_,"error in %s line %d: end of file in name",
- FileName,line);
- goto fin;
- }
- if(c=='\n')
- { efns(WARNING_,"error in %s line %d: line break in name",
- FileName,line);
- goto fin;
- }
- *n=c;
- }
- while((c=getc(f))==' ' || c=='\t' || c=='\r');
- if(c!='\n')
- { efns(WARNING_,"error in %s: garbage follows name line %d",
- FileName,line);
- goto fin;
- }
- else line++;
- *n=0;
- cellpop w;
- int x=0,y=0;
- while(strchr("\n\r .$\toO",c=getc(f)))switch(c)
- { case '\n':y++;x=0;line++;break;
- case '\r':break;
- case ' ':case '.':x++;break;
- case '$':x+=10;break;
- case '\t': x+=8-x%8;break;
- case 'o':case 'O':
- if(w.pop==MAXCELLS)
- { efns(WARNING_,"error in %s line %d: too many cells(%d)",
- FileName,line,MAXCELLS);
- goto fin;
- }
- temp[w.pop++]=cell_type(x,y);
- x++;break;
- default: efns(WARNING_,"error in %s line %d: invalid data",
- FileName, line);
- goto fin;
- }
- ungetc(c,f);
- w.v=copy(temp,w.pop);
- named_shape *temp=new named_shape;
- if(shapeptr)shapeptr->next=temp;
- temp->prev=shapeptr;
- shapeptr=temp;
- shapeidx++;
- shapeptr->next=NULL;
- shapeptr->name=strdup(name);
- shapeptr->shape=w;
- }
- fin: fclose(f);
- if(oldptr)
- { oldptr->next->prev=NULL;
- for(;oldptr;oldptr=oldptr->prev)shapeidx--;
- }
- return;
- }
-